/****************************** (C) COPYRIGHT 2016 RSEStudio ****************************
* File Name          : 
* Author             : RSES_Liyang
* Version            : V1.0.0
* Date               : 00-May-18
* Description        : 
*****************************************************************************************/
/* Includes ----------------------------------------------------------------------------*/
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "Bsp.h"
#include "button.h"
/* Extern variables --------------------------------------------------------------------*/
/* Private define ----------------------------------------------------------------------*/

#define BTN_STS_UP						1
#define BTN_STS_DOWN					2
#define BTN_STS_WAIT_DOUBLE				3
#define BTN_STS_WAIT_DOUBLE_RELEASE		4
#define BTN_STS_LONG					5
#define BTN_STS_LONG_FREE				6
#define BTN_STS_WAIT_IDLE				7

#define BTN_CTRL_ENABLE					(1<<0)
#define BTN_CTRL_CANCEL					(1<<1)
/* Private macro -----------------------------------------------------------------------*/

/* bit map button 'control flag'  */
/* High bit	:	15		14		13		12		11		10		9		8		*/
/* Flag		:																	*/
/* Low bit	:	7		6		5		4		3		2		1		0		*/
/* Flag		:												  CANCEL     EN		*/
/*	--------------- */
/* EN 		: 	0	-	Button is disable		*/
/* 	 		:	1	-	Button is enable		*/
/* WIDLE 	: 	0	-	Normal					*/
/* 	 		:	1	-	Wait this button idle   */

/* Private typedef ---------------------------------------------------------------------*/
/* Private variables -------------------------------------------------------------------*/
static uint16_t cur_btn_nbr;
btn_t *list_btn[BUTTON_MAX_NBR];
/* Private functions -------------------------------------------------------------------*/


/*****************************************************************************************
* Function Name  : cb_default
* Description    : 
* Input          : None
* Output         : None
* Return         : None
*****************************************************************************************/
static void cb_default(btn_t *btn,uint8_t Event)
{
	;
}

/*****************************************************************************************
* Function Name  : btn_init
* Description    : 
* Input          : None
* Output         : None
* Return         : None
*****************************************************************************************/
int btn_init(btn_t *btn, uint8_t(*read_btn_level)(void),cb_button cb)
{
	uint16_t i;
	if(btn == 0)
	{
		return -1;
	}
	
	if(read_btn_level == 0)
	{
		return -1;
	}
	
	for(i=0;i<BUTTON_MAX_NBR;i++)
	{
		if(list_btn[i] == btn)
		{
			return -2;
		}
	}
	
	if(cur_btn_nbr>=BUTTON_MAX_NBR)
	{
		return -3;
	}
	
	list_btn[cur_btn_nbr] = btn;
	
	btn->read_button_level = read_btn_level;
	
	if(cb == 0)
	{
		btn->callback_func = cb_default;
	}
	else
	{
		btn->callback_func = cb;
	}
	
	btn->change_flag = 0;
	btn->control_flag = 0;
	btn->debounce_timer = 0;
	
	cur_btn_nbr +=1;
	
	btn->control_flag |= BTN_CTRL_ENABLE;
	
	return 0;
}
//


/*****************************************************************************************
* Function Name  : btn_control
* Description    : 
* Input          : None
* Output         : None
* Return         : None
*****************************************************************************************/
int btn_control(btn_t *btn,uint16_t cmd,void *params)   
{
	int result = 0;
	int value;
	if(btn == 0)
	{
		return -1;
	}
	
	switch(cmd)
	{
		case BUTTON_CTL_ENABLE:
		{
			value = *(int*)params;
			if(value == 0)
			{
				btn->control_flag &= ~BTN_CTRL_ENABLE;
			}
			else
			{
				btn->control_flag |= BTN_CTRL_ENABLE;
			}
			
			result = 0;
		}break;
		
		case BUTTON_CTL_CANCEL_EVENT:
		{
			btn->control_flag |= BTN_CTRL_CANCEL;
			result = 0;
		}break;
		
		case BUTTON_CTL_GET_LEVEL:
		{
			value = *(int*)params;
			value = btn->level;
			result = 0;
		}break;
		
		case BUTTON_CTL_TRIGGER:
		{
			
		}break;
		
		default:
		{
			result = -2;
		}break;
	}
	return result;
}
//	


/*****************************************************************************************
* Function Name  : btn_process
* Description    : 
* Input          : None
* Output         : None
* Return         : None
*****************************************************************************************/
void btn_process(void)
{
	btn_t *p_btn;
	uint16_t polling_point;
	uint8_t current_level=0;
	
	for(polling_point=0;polling_point<cur_btn_nbr;polling_point++)
	{
		p_btn = list_btn[polling_point];
		if(p_btn == 0)
			continue;
		
		if((p_btn->control_flag&BTN_CTRL_ENABLE)==0)
			continue;
		
		if((p_btn->control_flag&BTN_CTRL_CANCEL)!=0)
		{
			p_btn->state = BTN_STS_WAIT_IDLE;
		}
		
		if(p_btn->read_button_level != 0)
		{
			current_level = p_btn->read_button_level();			
		}
				
		if(current_level != p_btn->level)
		{
			if(p_btn->debounce_timer++ >= BUTTON_DEBOUNCE_TIME)
			{
				
				p_btn->level = current_level;
				p_btn->debounce_timer = 0;
				p_btn->change_flag = 1;
				
				if(current_level != 0)
				{
					p_btn->callback_func(p_btn,BUTTON_EVENT_PRESS);
				}
//				else
//				{
//					p_btn->callback_func(p_btn,BUTTON_EVENT_RELEASE);
//				}
			}
		}
		
		switch(p_btn->state)
		{
			case BTN_STS_UP:
			{
				if(p_btn->change_flag !=0)
				{
					p_btn->change_flag = 0;
					
					if(current_level == 1)
					{
						p_btn->state = BTN_STS_DOWN;
						p_btn->long_timer = 0;
						p_btn->debounce_timer = 0;	
					}
				}
			}break;
			
			case BTN_STS_DOWN:
			{
				if(p_btn->change_flag !=0)
				{
					p_btn->change_flag = 0;
					
					if(current_level == 0)
					{
						p_btn->state = BTN_STS_WAIT_DOUBLE;
						p_btn->double_timer = 0;
						p_btn->callback_func(p_btn,BUTTON_EVENT_CLICK);
					}
				}
				else
				{
					if(p_btn->long_timer++>BUTTON_LONG_TIME)
					{
						p_btn->long_cycle_timer = 0;
						p_btn->state = BTN_STS_LONG;
						p_btn->callback_func(p_btn,BUTTON_EVENT_LONG);
					}
				}
			}break;
			
			case BTN_STS_WAIT_DOUBLE:
			{
				if(p_btn->change_flag !=0)
				{
					p_btn->change_flag = 0;
					
					if(current_level == 1)
					{
						p_btn->state = BTN_STS_WAIT_DOUBLE_RELEASE;
						p_btn->callback_func(p_btn,BUTTON_EVENT_DOUBLE);
					}
				}
				else
				{
					if(p_btn->double_timer++>BUTTON_DOUBLE_TIME)
					{
						p_btn->long_cycle_timer = 0;
						p_btn->state = BTN_STS_UP;
						p_btn->callback_func(p_btn,BUTTON_EVENT_ONLY_CLICK);
					}
				}
			}break;
			
			case BTN_STS_WAIT_DOUBLE_RELEASE:
			{
				if(p_btn->change_flag !=0)
				{
					p_btn->change_flag = 0;
					
					if(current_level == 0)
					{
						p_btn->state = BTN_STS_UP;
					}
				}
			}break;
			
			case BTN_STS_LONG:
			{
				if(p_btn->change_flag !=0)
				{
					p_btn->change_flag = 0;
					
					if(current_level == 0)
					{
						p_btn->state = BTN_STS_UP;
						p_btn->callback_func(p_btn,BUTTON_EVENT_LONG_FREE);
					}				
				}
				else
				{
					if(p_btn->long_cycle_timer++>BUTTON_LONG_CYCLE)
					{
						p_btn->long_cycle_timer = 0;
						p_btn->callback_func(p_btn,BUTTON_EVENT_LONG_REPEAT);
					}
				}
			}break;
			
			case BTN_STS_WAIT_IDLE:
			{
				if(current_level == 0)
				{
					p_btn->change_flag = 0;
					p_btn->double_timer = 0;
					p_btn->long_timer = 0;
					p_btn->long_cycle_timer = 0;
					p_btn->debounce_timer = 0;
					p_btn->state = BTN_STS_UP;
					p_btn->control_flag &= ~BTN_CTRL_CANCEL;
				}
			}break;
			
			default :
			{
				p_btn->change_flag = 0;
				p_btn->double_timer = 0;
				p_btn->long_timer = 0;
				p_btn->long_cycle_timer = 0;
				p_btn->debounce_timer = 0;
				p_btn->state = BTN_STS_UP;
			}break;
		}
		
	}
	
}

/********************************(C)COPYRIGHT 2016 RSEStudio ****************************/
/*****************************************END OF FILE************************************/
